package org.dezenho.server.RN;

import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import org.dezenho.server.SO.DezenhoServer;

/**
 * Classe Responsavel por representar a partida e todo o fluxo de informacoes
 * associada a ela
 * 
 * @author marcelasobrinhopereira
 * 
 */
public class Partida {

	private List<Jogador> jogadores;
	private Rodada rodada;
	private int contadorRodadas;
	private final int MAXRODADAS = 5;
	private Placar placar;
	private Integer idPartida;

	/**
	 * Contrutor
	 * 
	 * @param IdPartida
	 *            identifica a partida no servidor
	 * @param jogadores
	 */
	public Partida(List<Jogador> jogadores, Integer idPartida) {
		setIdPartida(idPartida);
		setJogadores(jogadores);
		for (Jogador jogador : jogadores) {
			jogador.setIdPartida(getIdPartida());
		}
		setPlacar(new Placar());
	}

	/**
	 * Metodo Responsavel por preparar contador e jogadores para a partida e
	 * iniciar primeira rodada
	 */
	public void iniciaPartida() {
		iniciaContadorRodadas();
		sorteiaPapeis();
		iniciaRodada();
	}

	/**
	 * Atualiza contador de partidas enquanto a partida nao chegou ao fim Caso
	 * tenha chegado ao fim, encerra partida
	 */
	public boolean atualizaContadorRodadas() {

		// Fim da partida
		if (getContadorRodadas() == 0) {
			Map<String, Integer> pontuacao = new HashMap<String, Integer>();
			for (Jogador jogador : getJogadores())
				pontuacao.put(jogador.getNome(), jogador.getPontuacao());

			for (Jogador jogador : getJogadores()) {
				try {
					jogador.getClient().apresentaResultadoPartida(pontuacao);
				} catch (RemoteException e) {
					DezenhoServer.getInstance().desconectaUsuario(
							jogador.getIPUsuario());
				}
				// Deixa o jogador pronto para nova partida
				jogador.setPapel(null);
				jogador.setPontuacao(0);
				jogador.setIdPartida(-1);
			}
			return false;
		} else {
			setContadorRodadas(getContadorRodadas() - 1);
			return true;
		}
	}

	/**
	 * Inicia uma nova rodada Altera a instancia da Rodada Atual para a recem
	 * criada
	 */
	public void iniciaRodada() {
		if (atualizaContadorRodadas()) {
			definePapeis();
			setRodada(new Rodada(this));
			getRodada().iniciaNovaRodada();
		}
	}

	/**
	 * Define quem sera o dessenhista e os adivinhadores inicialmente
	 */
	private void sorteiaPapeis() {

		Random geradorAleatorio = new Random();
		List<Jogador> jogadoresOrdenados = new ArrayList<Jogador>();
		int indice;
		jogadoresOrdenados.add(getJogadores().get(0));
		for (int i = 1; i < getJogadores().size(); i++) {
			indice = geradorAleatorio.nextInt(jogadoresOrdenados.size());
			/*
			 * adiciona numa posicao da lista, se estiver ocupada, afasta os
			 * demais
			 */
			jogadoresOrdenados.add(indice, getJogadores().get(i));
		}
		setJogadores(jogadoresOrdenados);
	}

	/**
	 * Redistribui os papeis a partir da ordem definida inicialmente
	 */
	private void definePapeis() {
		int indiceDesenhista;

		indiceDesenhista = getContadorRodadas() % 4;
		getJogadores().get(indiceDesenhista).setPapel(TipoJogador.DESENHINSTA);
		for (int indice = 0; indice <= 3; indice++) {
			if (indice != indiceDesenhista)
				getJogadores().get(indice).setPapel(TipoJogador.ADIVINHADOR);
		}
	}

	/**
	 * Inicia Contador com o total de rodadas
	 */
	private void iniciaContadorRodadas() {
		setContadorRodadas(MAXRODADAS);
	}

	// Metodos de Acesso

	public List<Jogador> getJogadores() {
		return jogadores;
	}

	public void setJogadores(List<Jogador> jogadores) {
		this.jogadores = jogadores;
	}

	public Rodada getRodada() {
		return rodada;
	}

	protected void setRodada(Rodada rodada) {
		this.rodada = rodada;
	}

	protected int getContadorRodadas() {
		return contadorRodadas;
	}

	protected void setContadorRodadas(int contadorRodadas) {
		this.contadorRodadas = contadorRodadas;
	}

	public Placar getPlacar() {
		return placar;
	}

	protected void setPlacar(Placar placar) {
		this.placar = placar;
	}

	public Integer getIdPartida() {
		return idPartida;
	}

	protected void setIdPartida(Integer idPartida) {
		this.idPartida = idPartida;
	}

	public void encerraPartida(Jogador jogadorDesconectado) {
		getJogadores().remove(jogadorDesconectado);
		for (Jogador jogador : getJogadores()) {
			jogador.setIdPartida(-1);
			jogador.setPapel(null);
			jogador.setPontuacao(0);
			try {
				jogador.getClient().apresentaResultadoPartida(
						new HashMap<String, Integer>());
			} catch (RemoteException e) {
				DezenhoServer.getInstance().desconectaUsuario(
						jogador.getIPUsuario());
			}
			DezenhoServer.getInstance().insereJogadorSalaEspera(
					jogador.getIPUsuario());
		}
	}

}
